<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="description" content="tong.li&#39;s blog">
  <meta name="keyword" content="彤哥哥博客，95后技术爱好者,现就职于同程旅行/同程艺龙上海分公司，专注于互联网技术分享的平台。">
  
    <link rel="shortcut icon" href="/css/images/icon.png">
  
  <title>
    
      浅谈Java对象四大引用 | 彤哥哥的博客
    
  </title>
  <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/highlight.js/9.12.0/styles/tomorrow-night.min.css" rel="stylesheet">
  
<link rel="stylesheet" href="/css/style.css">

  
  <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://cdn.staticfile.org/geopattern/1.2.3/js/geopattern.min.js"></script>
  <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
  
    
<script src="/js/qrious.js"></script>

  
  
  
  
    <!-- MathJax support START -->
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script type="text/javascript" src="https://cdn.staticfile.org/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <!-- MathJax support END -->
  


  
  
    
<script src="/js/local-search.js"></script>


<meta name="generator" content="Hexo 5.4.2"></head>
<div class="wechat-share">
  <img src="/css/images/logo.png" />
</div>
  <body>
    <header class="header fixed-header">
  <div class="header-container">
    <a class="home-link" href="/">
      <div class="logo"></div>
      <span>彤哥哥的博客</span>
    </a>
    <ul class="right-list">
      
        <li class="list-item">
          
            <a href="/" class="item-link">主页</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/series/" class="item-link">分类</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/tags/" class="item-link">标签</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/archives/" class="item-link">归档</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/project/" class="item-link">项目</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/about/" class="item-link">关于</a>
          
        </li>
      
      
        <li class="menu-item menu-item-search right-list">
    <a role="button" class="popup-trigger">
        <i class="fa fa-search fa-fw"></i>
    </a>
</li>
      
    </ul>
    <div class="menu">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </div>
    <div class="menu-mask">
      <ul class="menu-list">
        
          <li class="menu-item">
            
              <a href="/" class="menu-link">主页</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/series/" class="menu-link">分类</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/tags/" class="menu-link">标签</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/archives/" class="menu-link">归档</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/project/" class="menu-link">项目</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/about/" class="menu-link">关于</a>
            
          </li>
        
      </ul>
    </div>
    
      <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
            <span class="search-icon">
                <i class="fa fa-search"></i>
            </span>
            <div class="search-input-container">
                <input autocomplete="off" autocapitalize="off"
                    placeholder="Please enter your keyword(s) to search." spellcheck="false"
                    type="search" class="search-input">
            </div>
            <span class="popup-btn-close">
                <i class="fa fa-times-circle"></i>
            </span>
        </div>
        <div id="search-result">
            <div id="no-result">
                <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
            </div>
        </div>
    </div>
</div>
    
  </div>
</header>

    <div id="article-banner">
  <h2>浅谈Java对象四大引用</h2>
  <p class="post-date">2020-03-15</p>
  <div class="arrow-down">
    <a href="javascript:;"></a>
  </div>
</div>
<main class="app-body flex-box">
  <!-- Article START -->
  <article class="post-article">
    <section class="markdown-content"><h1 id="1-Java四大对象引用"><a href="#1-Java四大对象引用" class="headerlink" title="1. Java四大对象引用"></a>1. Java四大对象引用</h1><p>在jdk1.2之前，Java引用通俗意义上来讲就是对象引用和被引用的关系，实际定义为：如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址，就称该reference数据是代表某块内存、某个对象的引用。</p>
<p>在JDK1.2之后，Java对引用的概念将引用扩充为强引用(StronglyReference)、软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference)4种，这4种引用强度依次逐渐减弱。</p>
<h2 id="1-1-强引用-StronglyReference"><a href="#1-1-强引用-StronglyReference" class="headerlink" title="1.1 强引用(StronglyReference)"></a>1.1 强引用(StronglyReference)</h2><h3 id="1-1-1-概念定义"><a href="#1-1-1-概念定义" class="headerlink" title="1.1.1 概念定义"></a>1.1.1 概念定义</h3><ul>
<li>Object obj=new Object()这种引用赋值的关系就是强引用。</li>
<li>只要强引用关系还存在，垃圾收集器就永远不会回收掉被引用的对象。</li>
</ul>
<h3 id="1-1-2-代码演示"><a href="#1-1-2-代码演示" class="headerlink" title="1.1.2 代码演示"></a>1.1.2 代码演示</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desc</span> M实体</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> LT</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-03-15 20:34:17</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">M</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">finalize</span><span class="params">()</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="built_in">super</span>.finalize();</span><br><span class="line">        <span class="comment">// 这里只是演示，生产环境禁止重写改方法</span></span><br><span class="line">        System.out.println(<span class="string">&quot;---------作为M的我，被回收了-------------------&quot;</span>  + <span class="built_in">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desc</span> Java4大对象引用</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> LT</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-03-15 20:45:07</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ReferenceTest</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 强引用：</span></span><br><span class="line"><span class="comment">     *     直接new出来的对象直接赋值给引用</span></span><br><span class="line"><span class="comment">     *     当引用关系不存在的时，对象回收</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">stronglyReference</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 在堆里面new对象</span></span><br><span class="line">        <span class="type">M</span> <span class="variable">m</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">M</span>();</span><br><span class="line">        <span class="comment">// 引用还在</span></span><br><span class="line">        System.out.println(m);</span><br><span class="line">        <span class="comment">// 手动将引用设置为null</span></span><br><span class="line">        m = <span class="literal">null</span>;</span><br><span class="line">        <span class="comment">// 手动GC回收，M复写的finalize方法会调用，此时m对象会回收</span></span><br><span class="line">        System.gc();</span><br><span class="line">        <span class="comment">// 这个时候就获取到m就为null</span></span><br><span class="line">        System.out.println(m);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 执行结果</span></span><br><span class="line">com.java.entity.M@4ee285c6</span><br><span class="line">---------作为M的我，被回收了-------------------com.java.entity.M@4ee285c6</span><br><span class="line">null</span><br></pre></td></tr></table></figure>



<h2 id="1-2-软引用-SoftReference"><a href="#1-2-软引用-SoftReference" class="headerlink" title="1.2 软引用(SoftReference)"></a>1.2 软引用(SoftReference)</h2><h3 id="1-2-1-概念定义"><a href="#1-2-1-概念定义" class="headerlink" title="1.2.1 概念定义"></a>1.2.1 概念定义</h3><ul>
<li>软引用是用来描述一些还有用，但非必须的对象，典型案例就是缓存的应用。</li>
<li>只被软引用关联着的对象，在系统将要发生内存溢出异常前，会把这些对象列进回收范围之中进行第二次回收，如果这次回收还没有足够的内存，才会抛出内存溢出异常。</li>
<li>在JDK 1.2版之后提供了SoftReference类来实现软引用。</li>
</ul>
<h3 id="1-2-2-代码演示"><a href="#1-2-2-代码演示" class="headerlink" title="1.2.2 代码演示"></a>1.2.2 代码演示</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desc</span> M实体</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> LT</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-03-15 20:34:17</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">M</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 类加载时申请10M空间</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span>  <span class="type">byte</span>[] b = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">1024</span> * <span class="number">1024</span> * <span class="number">10</span>];</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">finalize</span><span class="params">()</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="built_in">super</span>.finalize();</span><br><span class="line">        System.out.println(<span class="string">&quot;---------作为M的我，被回收了-------------------&quot;</span> + <span class="built_in">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 软引用：</span></span><br><span class="line"><span class="comment"> *    被SoftReference类引用的对象，只有在空间不足的情况下进行GC回收。</span></span><br><span class="line"><span class="comment"> *    很适合做缓存。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">softReference</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">// 申请10M的空间，并给软引用</span></span><br><span class="line">    SoftReference&lt;M&gt; m = <span class="keyword">new</span> <span class="title class_">SoftReference</span>&lt;&gt;(<span class="keyword">new</span> <span class="title class_">M</span>());</span><br><span class="line">    <span class="comment">// 可以打印出字节数组对象</span></span><br><span class="line">    System.out.println(m.get());</span><br><span class="line">    System.gc();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 睡眠500毫秒，等待GC回收</span></span><br><span class="line">        TimeUnit.MILLISECONDS.sleep(<span class="number">500</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 继续打印</span></span><br><span class="line">    System.out.println(m.get());</span><br><span class="line">    <span class="comment">// 再分配一个15M字节数组,heap不够,这个时候系统会垃圾回收，先回收一次，如果不够，会把软引用的对象回收掉</span></span><br><span class="line">    <span class="type">byte</span>[] b = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">1024</span> * <span class="number">1024</span> * <span class="number">15</span>];</span><br><span class="line">    <span class="comment">// 继续打印</span></span><br><span class="line">    System.out.println(m.get());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 直接运行都可以打印出相同的对象</span></span><br><span class="line">com.java.entity.M@4ee285c6</span><br><span class="line">com.java.entity.M@4ee285c6</span><br><span class="line">com.java.entity.M@4ee285c6</span><br><span class="line"><span class="comment"># 当在启动时候加上JVM参数-Xmx20M时，会回收报堆内存不足，此时会回收软引用的对象</span></span><br><span class="line">com.java.entity.M@4ee285c6</span><br><span class="line">com.java.entity.M@4ee285c6</span><br><span class="line">---------作为M的我，被回收了-------------------com.java.entity.M@4ee285c6</span><br><span class="line"></span><br><span class="line">java.lang.OutOfMemoryError: Java heap space</span><br><span class="line">	at com.java.reference.ReferenceTest.softReference(ReferenceTest.java:57)</span><br></pre></td></tr></table></figure>



<h2 id="1-3-弱引用-WeakReference"><a href="#1-3-弱引用-WeakReference" class="headerlink" title="1.3 弱引用(WeakReference)"></a>1.3 弱引用(WeakReference)</h2><h3 id="1-3-1-概念定义"><a href="#1-3-1-概念定义" class="headerlink" title="1.3.1 概念定义"></a>1.3.1 概念定义</h3><ul>
<li>弱引用也是用来描述那些非必须对象，但是它的强度比软引用更弱一些，被弱引用关联的对象只能生存到下一次垃圾收集发生为止。</li>
<li>当垃圾收集器开始工作，无论当前内存是否足够，都会回收掉只被弱引用关联的对象。</li>
<li>在JDK 1.2版之后提供了WeakReference类来实现弱引用。</li>
</ul>
<h3 id="1-3-2-代码演示"><a href="#1-3-2-代码演示" class="headerlink" title="1.3.2 代码演示"></a>1.3.2 代码演示</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 弱引用：</span></span><br><span class="line"><span class="comment"> *    被WeakReference类引用的对象，只要有GC都回收该对象。</span></span><br><span class="line"><span class="comment"> *    ThreadLocal就是典型的应用</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">weakReference</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">// 创建虚弱引用对象，并指向M对象</span></span><br><span class="line">    WeakReference&lt;M&gt; m = <span class="keyword">new</span> <span class="title class_">WeakReference</span>&lt;&gt;(<span class="keyword">new</span> <span class="title class_">M</span>());</span><br><span class="line">    <span class="comment">// 可以获取到m对象</span></span><br><span class="line">    System.out.println(m.get());</span><br><span class="line">    <span class="comment">// GC垃圾回收</span></span><br><span class="line">    System.gc();</span><br><span class="line">    <span class="comment">// 已经无法获取到m对象</span></span><br><span class="line">    System.out.println(m.get());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 运行结果</span></span><br><span class="line">com.java.entity.M@4ee285c6</span><br><span class="line">null</span><br><span class="line">---------作为M的我，被回收了-------------------com.java.entity.M@4ee285c6</span><br></pre></td></tr></table></figure>



<h2 id="1-4-虚引用-PhantomReference"><a href="#1-4-虚引用-PhantomReference" class="headerlink" title="1.4 虚引用(PhantomReference)"></a>1.4 虚引用(PhantomReference)</h2><h3 id="1-4-1-概念定义"><a href="#1-4-1-概念定义" class="headerlink" title="1.4.1 概念定义"></a>1.4.1 概念定义</h3><ul>
<li>虚引用也称为“幽灵引用”或者“幻影引用”，它是最弱的一种引用关系。</li>
<li>一个对象是否有虚引用的存在，完全不会对其生存时间构成影响，也无法通过虚引用来取得一个对象实例。</li>
<li>为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。</li>
<li>在JDK 1.2版之后提供了PhantomReference类来实现虚引用。</li>
</ul>
<h3 id="1-4-2-代码演示"><a href="#1-4-2-代码演示" class="headerlink" title="1.4.2 代码演示"></a>1.4.2 代码演示</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.java.reference;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.java.entity.M;</span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"><span class="keyword">import</span> java.lang.ref.*;</span><br><span class="line"><span class="keyword">import</span> java.util.LinkedList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ExecutorService;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Executors;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desc</span> Java4对象大引用</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> LT</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020-03-15 20:45:07</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ReferenceTest</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 对象列表</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> List&lt;Object&gt; LIST = <span class="keyword">new</span> <span class="title class_">LinkedList</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 引用队列</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> ReferenceQueue&lt;M&gt; QUEUE = <span class="keyword">new</span> <span class="title class_">ReferenceQueue</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 虚引用：</span></span><br><span class="line"><span class="comment">     *    被PhantomReference类引用的对象，堆外内存的回收。</span></span><br><span class="line"><span class="comment">     *    JVM进行垃圾回收的时候，不会立即回收该对象引用，而会把该对象的引用放入队列中等待其他线程处理</span></span><br><span class="line"><span class="comment">     *    Netty中DirectBuffer内存区就属于堆外内存。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">phantomReference</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 创建虚引用对象，并指定存放M对象，将回收引用放入QUEUE</span></span><br><span class="line">        PhantomReference&lt;M&gt; phantomReference = <span class="keyword">new</span> <span class="title class_">PhantomReference</span>&lt;&gt;(<span class="keyword">new</span> <span class="title class_">M</span>(), QUEUE);</span><br><span class="line">        <span class="comment">// 创建线程池，核心线程数2个</span></span><br><span class="line">        <span class="type">ExecutorService</span> <span class="variable">threadPool</span> <span class="operator">=</span> Executors.newFixedThreadPool(<span class="number">2</span>);</span><br><span class="line">        <span class="comment">// 第一个用于存储对象</span></span><br><span class="line">        threadPool.execute(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">                LIST.add(<span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">1024</span> * <span class="number">1024</span>]);</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                    Thread.currentThread().interrupt();</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 这里永远get到的结果为null，虚引用在堆内存就是没有意义</span></span><br><span class="line">                System.out.println(phantomReference.get());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 队列检测通知</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        threadPool.execute(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">                <span class="comment">// 获取队列的引用</span></span><br><span class="line">                Reference&lt;? <span class="keyword">extends</span> <span class="title class_">M</span>&gt; poll = QUEUE.poll();</span><br><span class="line">                <span class="keyword">if</span> (poll != <span class="literal">null</span>) &#123;</span><br><span class="line">                    <span class="comment">// 引用回收通知</span></span><br><span class="line">                    System.out.println(<span class="string">&quot;-------虚引用对象被回收了-------------&quot;</span> + poll);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 等待GC回收</span></span><br><span class="line">            threadPool.awaitTermination(<span class="number">1</span>,TimeUnit.DAYS);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 这里设置一下-Xmx20M,不然一直创建对象内存会爆掉，这里设置堆大小跟虚引用没任何关系，只是为了演示效果</span></span><br><span class="line"><span class="comment"># 应用刚启动，就回收了虚引用对象，所以说虚引用创建起来并没有什么实际用处，一直get为null，只是为了回收通知</span></span><br><span class="line">---------作为M的我，被回收了-------------------com.java.entity.M@32a48caa</span><br><span class="line">null</span><br><span class="line">null</span><br><span class="line">null</span><br><span class="line">null</span><br><span class="line">null</span><br><span class="line">null</span><br><span class="line">-------虚引用对象被回收了-------------java.lang.ref.PhantomReference@113fd376</span><br><span class="line">null</span><br><span class="line">Exception <span class="keyword">in</span> thread <span class="string">&quot;pool-1-thread-1&quot;</span> java.lang.OutOfMemoryError: Java heap space</span><br><span class="line">	at com.java.reference.ReferenceTest.lambda$phantomReference<span class="variable">$0</span>(ReferenceTest.java:111)</span><br><span class="line">	at com.java.reference.ReferenceTest$$Lambda<span class="variable">$1</span>/1562557367.run(Unknown Source)</span><br><span class="line">	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)</span><br><span class="line">	at java.util.concurrent.ThreadPoolExecutor<span class="variable">$Worker</span>.run(ThreadPoolExecutor.java:624)</span><br><span class="line">	at java.lang.Thread.run(Thread.java:748)</span><br></pre></td></tr></table></figure>

<h1 id="2-引用的应用剖析"><a href="#2-引用的应用剖析" class="headerlink" title="2. 引用的应用剖析"></a>2. 引用的应用剖析</h1><h2 id="2-1-ThreadLocal中的弱引用应用"><a href="#2-1-ThreadLocal中的弱引用应用" class="headerlink" title="2.1 ThreadLocal中的弱引用应用"></a>2.1 ThreadLocal中的弱引用应用</h2><ol>
<li><p>熟悉ThreadLocal源码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ThreadLocal</span>&lt;T&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> T <span class="title function_">get</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">Thread</span> <span class="variable">t</span> <span class="operator">=</span> Thread.currentThread();  <span class="comment">// 获取当前线程</span></span><br><span class="line">        <span class="type">ThreadLocalMap</span> <span class="variable">map</span> <span class="operator">=</span> getMap(t); <span class="comment">// 获取当前线程threadLocals变量，其实就是Thread的成员变量</span></span><br><span class="line">        <span class="keyword">if</span> (map != <span class="literal">null</span>) &#123;  <span class="comment">// 如果获取到map</span></span><br><span class="line">            ThreadLocalMap.<span class="type">Entry</span> <span class="variable">e</span> <span class="operator">=</span> map.getEntry(<span class="built_in">this</span>); <span class="comment">// 通过当前TheadLocal对象作为key获取value</span></span><br><span class="line">            <span class="keyword">if</span> (e != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">                <span class="type">T</span> <span class="variable">result</span> <span class="operator">=</span> (T)e.value; <span class="comment">// 泛型检查</span></span><br><span class="line">                <span class="keyword">return</span> result;  <span class="comment">// 返回vaue</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> setInitialValue();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">set</span><span class="params">(T value)</span> &#123;</span><br><span class="line">        <span class="type">Thread</span> <span class="variable">t</span> <span class="operator">=</span> Thread.currentThread();  <span class="comment">// 获取当前线程对象</span></span><br><span class="line">        <span class="type">ThreadLocalMap</span> <span class="variable">map</span> <span class="operator">=</span> getMap(t);  <span class="comment">// 获取当前线程threadLocals变量</span></span><br><span class="line">        <span class="keyword">if</span> (map != <span class="literal">null</span>)  <span class="comment">// 如果不为空，将当前ThreadLocal作为key，组成ThreadLocalMap.Entry对象</span></span><br><span class="line">            map.set(<span class="built_in">this</span>, value);</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            createMap(t, value);  <span class="comment">// 创建线程ThreadLocalMap对象，并存放ThreadLocal和value</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">remove</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">ThreadLocalMap</span> <span class="variable">m</span> <span class="operator">=</span> getMap(Thread.currentThread()); <span class="comment">// 获取当前线程对象</span></span><br><span class="line">        <span class="keyword">if</span> (m != <span class="literal">null</span>)   </span><br><span class="line">            m.remove(<span class="built_in">this</span>);  <span class="comment">// 根据当前ThreadLocal对象移除对象</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ThreadLocalMap <span class="title function_">getMap</span><span class="params">(Thread t)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> t.threadLocals;  <span class="comment">// 从线程中获取threadLocals变量</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">createMap</span><span class="params">(Thread t, T firstValue)</span> &#123;</span><br><span class="line">        t.threadLocals = <span class="keyword">new</span> <span class="title class_">ThreadLocalMap</span>(<span class="built_in">this</span>, firstValue); <span class="comment">// 直接创建一个本地的ThreadLocalMap</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">ThreadLocalMap</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Entry</span> <span class="keyword">extends</span> <span class="title class_">WeakReference</span>&lt;ThreadLocal&lt;?&gt;&gt; &#123;  <span class="comment">// 这里采用弱引用</span></span><br><span class="line">            <span class="comment">/** The value associated with this ThreadLocal. */</span></span><br><span class="line">            Object value;  <span class="comment">// 这个value和当前ThreadLocal关联</span></span><br><span class="line"></span><br><span class="line">            Entry(ThreadLocal&lt;?&gt; k, Object v) &#123;</span><br><span class="line">                <span class="built_in">super</span>(k);</span><br><span class="line">                value = v;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">       <span class="keyword">private</span> Entry <span class="title function_">getEntry</span><span class="params">(ThreadLocal&lt;?&gt; key)</span> &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> key.threadLocalHashCode &amp; (table.length - <span class="number">1</span>);</span><br><span class="line">            <span class="type">Entry</span> <span class="variable">e</span> <span class="operator">=</span> table[i];</span><br><span class="line">            <span class="keyword">if</span> (e != <span class="literal">null</span> &amp;&amp; e.get() == key)</span><br><span class="line">                <span class="keyword">return</span> e;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                <span class="keyword">return</span> getEntryAfterMiss(key, i, e);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">private</span> Entry <span class="title function_">getEntryAfterMiss</span><span class="params">(ThreadLocal&lt;?&gt; key, <span class="type">int</span> i, Entry e)</span> &#123;</span><br><span class="line">            Entry[] tab = table;</span><br><span class="line">            <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> tab.length;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">while</span> (e != <span class="literal">null</span>) &#123;</span><br><span class="line">                ThreadLocal&lt;?&gt; k = e.get();</span><br><span class="line">                <span class="keyword">if</span> (k == key)</span><br><span class="line">                    <span class="keyword">return</span> e;</span><br><span class="line">                <span class="keyword">if</span> (k == <span class="literal">null</span>)</span><br><span class="line">                    expungeStaleEntry(i);</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                    i = nextIndex(i, len);</span><br><span class="line">                e = tab[i];</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">         <span class="keyword">private</span> <span class="type">int</span> <span class="title function_">expungeStaleEntry</span><span class="params">(<span class="type">int</span> staleSlot)</span> &#123;</span><br><span class="line">            Entry[] tab = table;</span><br><span class="line">            <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> tab.length;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// expunge entry at staleSlot</span></span><br><span class="line">            tab[staleSlot].value = <span class="literal">null</span>; </span><br><span class="line">            tab[staleSlot] = <span class="literal">null</span>;</span><br><span class="line">            size--;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Rehash until we encounter null  直到我们null再rehash一次</span></span><br><span class="line">            Entry e;</span><br><span class="line">            <span class="type">int</span> i;</span><br><span class="line">            <span class="keyword">for</span> (i = nextIndex(staleSlot, len);</span><br><span class="line">                 (e = tab[i]) != <span class="literal">null</span>;</span><br><span class="line">                 i = nextIndex(i, len)) &#123;</span><br><span class="line">                ThreadLocal&lt;?&gt; k = e.get();</span><br><span class="line">                <span class="keyword">if</span> (k == <span class="literal">null</span>) &#123;  <span class="comment">// 找到ThreadLocal指向为null的key</span></span><br><span class="line">                    e.value = <span class="literal">null</span>;  <span class="comment">// 当key引用为null，对象已回收，释放空间，一定程度上解决内存泄露</span></span><br><span class="line">                    tab[i] = <span class="literal">null</span>;</span><br><span class="line">                    size--;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="type">int</span> <span class="variable">h</span> <span class="operator">=</span> k.threadLocalHashCode &amp; (len - <span class="number">1</span>);</span><br><span class="line">                    <span class="keyword">if</span> (h != i) &#123;</span><br><span class="line">                        tab[i] = <span class="literal">null</span>;</span><br><span class="line">                        <span class="comment">// Unlike Knuth 6.4 Algorithm R, we must scan until</span></span><br><span class="line">                        <span class="comment">// null because multiple entries could have been stale.</span></span><br><span class="line">                        <span class="keyword">while</span> (tab[h] != <span class="literal">null</span>)</span><br><span class="line">                            h = nextIndex(h, len);</span><br><span class="line">                        tab[h] = e;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> i;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">remove</span><span class="params">(ThreadLocal&lt;?&gt; key)</span> &#123;</span><br><span class="line">         Entry[] tab = table;</span><br><span class="line">            <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> tab.length;</span><br><span class="line">         <span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> key.threadLocalHashCode &amp; (len-<span class="number">1</span>);</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">Entry</span> <span class="variable">e</span> <span class="operator">=</span> tab[i];</span><br><span class="line">                 e != <span class="literal">null</span>;</span><br><span class="line">                 e = tab[i = nextIndex(i, len)]) &#123;</span><br><span class="line">                <span class="keyword">if</span> (e.get() == key) &#123;  <span class="comment">// 假设有一个map中有一个e.get()和key永远不等，因为一个ThreadLocal的生命周期和对应的Thread周期是一致的，线程结束掉，Thread就会死掉，Thread中的成员变量threadLocas就获取不到，ThreadLocal对象也会回收，所以会存在内存泄露</span></span><br><span class="line">                    e.clear();  <span class="comment">// 移除当前线程变量数据</span></span><br><span class="line">                    expungeStaleEntry(i); </span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li><p>ThreadLocal分析与总结</p>
<p> 为什么ThreadLocal中的ThreadLocalMap.Entry要使用弱引用？</p>
<ul>
<li>若是强引用，即使threadLocal对象强制设置为null，但key的引用依然指向ThreadLocal对象，所以会有内存泄露，而使用弱引用则不会。</li>
<li>但是还有内存泄露存在的可能，ThreadLocal被回收，key的值变为null，则导致整个value再也无法被访问到，因此依然存在内存泄露。</li>
<li>为了使ThreadLocal对象回收，我们尽可能不要定义static的ThreadLocal对象，不要延长它的生命周期。另外，尽可能手动调用remove方法提前通知JVM回收</li>
</ul>
</li>
</ol>
<h1 id="3-参考文档"><a href="#3-参考文档" class="headerlink" title="3. 参考文档"></a>3. 参考文档</h1><ul>
<li><a target="_blank" rel="noopener" href="https://read.douban.com/ebook/128052544/?from=groupmessage">《深入理解JVM虚拟机：JVM高级特性与最佳实践(第3版)》周志明著</a></li>
</ul>
</section>
    <!-- Tags START -->
    
      <div class="tags">
        <span>Tags:</span>
        
  <a href="/tags#Java" >
    <span class="tag-code">Java</span>
  </a>

      </div>
    
    <!-- Tags END -->
    <!-- NAV START -->
    
  <div class="nav-container">
    <!-- reverse left and right to put prev and next in a more logic postition -->
    
      <a class="nav-left" href="/2020/02/11/%E5%89%8D%E7%AB%AF%E6%9E%84%E5%BB%BA%E5%B7%A5%E5%85%B7webpack%E5%85%A5%E9%97%A8/">
        <span class="nav-arrow">← </span>
        
          前端构建工具webpack入门
        
      </a>
    
    
      <a class="nav-right" href="/2020/04/01/%E4%BA%86%E8%A7%A3%E5%B8%B8%E8%A7%81%E7%9A%84Redis%E9%9B%86%E7%BE%A4%E6%96%B9%E5%BC%8F/">
        
          了解常见的Redis集群方式
        
        <span class="nav-arrow"> →</span>
      </a>
    
  </div>

    <!-- NAV END -->
    <!-- 打赏 START -->
    
      <div class="money-like">
        <div class="reward-btn">
          赏
          <span class="money-code">
            <span class="alipay-code">
              <div class="code-image"></div>
              <b>使用支付宝打赏</b>
            </span>
            <span class="wechat-code">
              <div class="code-image"></div>
              <b>使用微信打赏</b>
            </span>
          </span>
        </div>
        <p class="notice">若你觉得我的文章对你有帮助，欢迎点击上方按钮对我打赏</p>
      </div>
    
    <!-- 打赏 END -->
    <!-- 二维码 START -->
    
      <div class="qrcode">
        <canvas id="share-qrcode"></canvas>
        <p class="notice">扫描二维码，分享此文章</p>
      </div>
    
    <!-- 二维码 END -->
    
      <!-- Utterances START -->
      <div id="utterances"></div>
      <script src="https://utteranc.es/client.js"
        repo="ltyeamin/blogtalks"
        issue-term="pathname"
        theme="github-light"
        crossorigin="anonymous"
        async></script>    
      <!-- Utterances END -->
    
  </article>
  <!-- Article END -->
  <!-- Catalog START -->
  
    <aside class="catalog-container">
  <div class="toc-main">
    <strong class="toc-title">Catalog</strong>
    
      <ol class="toc-nav"><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#1-Java%E5%9B%9B%E5%A4%A7%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A8"><span class="toc-nav-text">1. Java四大对象引用</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-1-%E5%BC%BA%E5%BC%95%E7%94%A8-StronglyReference"><span class="toc-nav-text">1.1 强引用(StronglyReference)</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-1-1-%E6%A6%82%E5%BF%B5%E5%AE%9A%E4%B9%89"><span class="toc-nav-text">1.1.1 概念定义</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-1-2-%E4%BB%A3%E7%A0%81%E6%BC%94%E7%A4%BA"><span class="toc-nav-text">1.1.2 代码演示</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-2-%E8%BD%AF%E5%BC%95%E7%94%A8-SoftReference"><span class="toc-nav-text">1.2 软引用(SoftReference)</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-2-1-%E6%A6%82%E5%BF%B5%E5%AE%9A%E4%B9%89"><span class="toc-nav-text">1.2.1 概念定义</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-2-2-%E4%BB%A3%E7%A0%81%E6%BC%94%E7%A4%BA"><span class="toc-nav-text">1.2.2 代码演示</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-3-%E5%BC%B1%E5%BC%95%E7%94%A8-WeakReference"><span class="toc-nav-text">1.3 弱引用(WeakReference)</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-3-1-%E6%A6%82%E5%BF%B5%E5%AE%9A%E4%B9%89"><span class="toc-nav-text">1.3.1 概念定义</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-3-2-%E4%BB%A3%E7%A0%81%E6%BC%94%E7%A4%BA"><span class="toc-nav-text">1.3.2 代码演示</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-4-%E8%99%9A%E5%BC%95%E7%94%A8-PhantomReference"><span class="toc-nav-text">1.4 虚引用(PhantomReference)</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-4-1-%E6%A6%82%E5%BF%B5%E5%AE%9A%E4%B9%89"><span class="toc-nav-text">1.4.1 概念定义</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-4-2-%E4%BB%A3%E7%A0%81%E6%BC%94%E7%A4%BA"><span class="toc-nav-text">1.4.2 代码演示</span></a></li></ol></li></ol></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#2-%E5%BC%95%E7%94%A8%E7%9A%84%E5%BA%94%E7%94%A8%E5%89%96%E6%9E%90"><span class="toc-nav-text">2. 引用的应用剖析</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#2-1-ThreadLocal%E4%B8%AD%E7%9A%84%E5%BC%B1%E5%BC%95%E7%94%A8%E5%BA%94%E7%94%A8"><span class="toc-nav-text">2.1 ThreadLocal中的弱引用应用</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#3-%E5%8F%82%E8%80%83%E6%96%87%E6%A1%A3"><span class="toc-nav-text">3. 参考文档</span></a></li></ol>
    
  </div>
</aside>
  
  <!-- Catalog END -->
</main>

<script>
  (function () {
    var url = 'http://example.com/2020/03/15/浅谈Java对象四大引用/';
    var banner = ''
    if (banner !== '' && banner !== 'undefined' && banner !== 'null') {
      $('#article-banner').css({
        'background-image': 'url(' + banner + ')'
      })
    } else {
      $('#article-banner').geopattern(url)
    }
    $('.header').removeClass('fixed-header')

    // error image
    $(".markdown-content img").on('error', function() {
      $(this).attr('src', '/css/images/error_icon.png')
      $(this).css({
        'cursor': 'default'
      })
    })

    // zoom image
    $(".markdown-content img").on('click', function() {
      var src = $(this).attr('src')
      if (src !== '/css/images/error_icon.png') {
        var imageW = $(this).width()
        var imageH = $(this).height()

        var zoom = ($(window).width() * 0.95 / imageW).toFixed(2)
        zoom = zoom < 1 ? 1 : zoom
        zoom = zoom > 2 ? 2 : zoom
        var transY = (($(window).height() - imageH) / 2).toFixed(2)

        $('body').append('<div class="image-view-wrap"><div class="image-view-inner"><img src="'+ src +'" /></div></div>')
        $('.image-view-wrap').addClass('wrap-active')
        $('.image-view-wrap img').css({
          'width': `${imageW}`,
          'transform': `translate3d(0, ${transY}px, 0) scale3d(${zoom}, ${zoom}, 1)`
        })
        $('html').css('overflow', 'hidden')

        $('.image-view-wrap').on('click', function() {
          $(this).remove()
          $('html').attr('style', '')
        })
      }
    })
  })();
</script>


  <script>
    var qr = new QRious({
      element: document.getElementById('share-qrcode'),
      value: document.location.href
    });
  </script>






    <div class="scroll-top">
  <span class="arrow-icon"></span>
</div>
    <footer class="app-footer">
  <p class="copyright">
    &copy; 2024 | Proudly powered by <a href="https://hexo.io" target="_blank">Hexo</a>
    <br>
    Theme by <a target="_blank" rel="noopener" href="https://github.com/ltyeamin">tong.li</a>
  </p>
</footer>

<script>
  function async(u, c) {
    var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
    s.parentNode.insertBefore(o, s);
  }
</script>
<script>
  async("https://cdn.staticfile.org/fastclick/1.0.6/fastclick.min.js", function(){
    FastClick.attach(document.body);
  })
</script>

<script>
  var hasLine = 'true';
  async("https://cdn.staticfile.org/highlight.js/9.12.0/highlight.min.js", function(){
    $('figure pre').each(function(i, block) {
      var figure = $(this).parents('figure');
      if (hasLine === 'false') {
        figure.find('.gutter').hide();
      }
      hljs.configure({useBR: true});
      var lang = figure.attr('class').split(' ')[1] || 'code';
      var codeHtml = $(this).html();
      var codeTag = document.createElement('code');
      codeTag.className = lang;
      codeTag.innerHTML = codeHtml;
      $(this).attr('class', '').empty().html(codeTag);
      figure.attr('data-lang', lang.toUpperCase());
      hljs.highlightBlock(block);
    });
  })
</script>
<!-- Baidu Tongji -->



<script src='https://cdn.staticfile.org/mermaid/8.11.2/mermaid.min.js'></script>



<script src="/js/script.js"></script>


  </body>
</html>